#pragma once

#include <unordered_map>
#include <string>
#include <vector>
#include <sstream>

class HTTPRequestLine
{
    enum class all_method
    {
        GET,
        PUT,
        OPTIONS,
        HEAD,
        TRACE,
    };

    std::unordered_map<all_method, std::string> method_str_map{
        {all_method::GET, "GET"},
        {all_method::PUT, "PUT"},
        {all_method::OPTIONS, "OPTIONS"},
        {all_method::HEAD, "HEAD"},
        {all_method::TRACE, "TRACE"}};

public:
    using Method = all_method;

private:
    Method method;
    std::string path;
    std::string http_version;

public:
    HTTPRequestLine(Method m = Method::GET, const std::string &path = "/", const std::string http_version = "1.1");

    std::string to_string();

    Method get_method() const;

    Method set_method(Method m);

    const std::string &get_path() const;

    std::string set_path(const std::string &new_path);
};

class HTTPHeader
{
    enum class header_key
    {
        USER_AGENT,
        HOST,
        CONNECTION
    };

    std::unordered_map<header_key, std::string> header_name{
        {header_key::USER_AGENT, "User-Agent"},
        {header_key::HOST, "Host"},
        {header_key::CONNECTION, "Connection"}};

private:
    std::string name;
    std::string value;

public:
    using Keys = header_key;
    HTTPHeader(Keys header, const std::string &value = "");

    std::string to_string() const;
};

class HTTPRequest
{
private:
    HTTPRequestLine request_line;
    std::vector<HTTPHeader> headers;

public:
    HTTPRequest(const HTTPRequestLine &request_line,
                const std::vector<HTTPHeader> &headers);

    HTTPRequest();

    void set_method(HTTPRequestLine::Method m);

    std::string to_string();

    explicit operator const std::string();

    void append_header(const HTTPHeader &header);

    void append_header(HTTPHeader::Keys header, const std::string &value);

    const HTTPRequestLine &get_request_line() const;

    friend std::ostream &operator<<(std::ostream &os, const HTTPRequest &request);
};

std::ostream &operator<<(std::ostream &os, HTTPRequest &request);